package com.gitee.wsl.struct.grammar.parser.tokenizer

import com.gitee.wsl.struct.grammar.annotations.ExperimentalParsusApi
import com.gitee.wsl.struct.grammar.parser.token.Token
import com.gitee.wsl.struct.grammar.parser.token.TokenMatch
import com.gitee.wsl.struct.grammar.parser.trace.TokenMatchingEvent
import com.gitee.wsl.struct.grammar.parser.trace.TokenMatchingTrace

@OptIn(ExperimentalParsusApi::class)
internal abstract class AbstractTokenizer(
    override var input: String,
    protected val tokens: List<Token>,
    traceTokenMatching: Boolean = false,
) : Tokenizer {

    constructor(tokens: List<Token>,traceTokenMatching: Boolean = false,):this("",tokens,traceTokenMatching)

    private var traceEvents: MutableList<TokenMatchingEvent>? = if (traceTokenMatching) mutableListOf() else null

    override fun reset(input: String, traceTokenMatching: Boolean){
        this.input = input
        traceEvents = if (traceTokenMatching) mutableListOf() else null
    }

    override fun getTokenMatchingTrace(): TokenMatchingTrace? {
        return traceEvents?.let { TokenMatchingTrace(input, it) }
    }

    protected fun matchImpl(fromIndex: Int, token: Token): TokenMatch? {
        val length = token.match(input, fromIndex)
        if (length == 0) {
            traceMismatch(token, fromIndex)
            return null
        }

        val match = TokenMatch(token, fromIndex, length)
        traceMatch(token, match)
        return match
    }

    private fun traceMismatch(token: Token, offset: Int) {
        traceEvents?.add(TokenMatchingEvent(token, offset, null))
    }

    private fun traceMatch(token: Token, match: TokenMatch) {
        traceEvents?.add(TokenMatchingEvent(token, match.offset, match))
    }
}
